package com.wxmp.wxapi.ctrl;


import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.github.binarywang.wxpay.util.SignUtils;
import com.wxmp.core.common.BaseCtrl;
import com.wxmp.core.common.Constants;
import com.wxmp.core.common.PayConstant;
import com.wxmp.core.util.AjaxResult;
import com.wxmp.core.util.StringUtil;
import com.wxmp.core.util.keyGenerator.DefaultKeyGenerator;
import com.wxmp.core.util.wx.WxPayProperties;
import com.wxmp.wxapi.domain.WxpayOrder;
import com.wxmp.wxapi.process.WxMemoryCacheClient;
import com.wxmp.wxapi.service.WxRechargeService;
import com.wxmp.wxapi.service.WxUserService;
import com.wxmp.wxapi.vo.PayRecord;
import com.wxmp.wxapi.vo.RechargeOrder;
import com.wxmp.wxapi.vo.UnionCardAccount;
import com.wxmp.wxcms.ctrl.WxPayCtrl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Johnkee
 */
@Controller
@RequestMapping("/wxpay")
public class WxUserPayCtrl extends BaseCtrl {

    private static final Logger log = LoggerFactory.getLogger(WxPayCtrl.class);

    @Autowired
    private WxRechargeService wxRechargeService;

    @Autowired
    private WxUserService wxUserService;

    @Resource
    private WxPayProperties wxPayProperties;


    static final String MCH_ID = "20190101";

    /**
     * wx menu gateway
     *
     * @throws Exception
     */
    @RequestMapping("/recharge.html")
    public void openRecharge() throws Exception {
        String openid = WxMemoryCacheClient.getOpenid(request.getSession().getId());
        log.info("openid:" + openid);
        if (StringUtils.isEmpty(openid)) {
            response.sendRedirect("/views/mp/recharge/failure.html?msg=" + Constants.MSG_ERROR);
        } else {
            UnionCardAccount unionCardAccount = wxRechargeService.getCardAccount(openid);
            if (unionCardAccount == null) {
                response.sendRedirect("/views/mp/recharge/bindCard.html");
            } else {
                response.sendRedirect("/views/mp/recharge/recharge.html");
            }
        }
    }

    @RequestMapping(value = "/getCardOwnerByCardNo", method = RequestMethod.POST)
    @ResponseBody
    public AjaxResult getCardOwnerByCardNo(String cardNo) {
        String cardOwner = wxRechargeService.getCardOwnerByCardNo(cardNo);
        if (StringUtil.isNotEmpty(cardOwner)) {
            return AjaxResult.success(cardOwner);
        } else {
            return AjaxResult.failure("卡号没有对应的持卡人，请检查卡号输入是否准确");
        }
    }

    @RequestMapping(value = "/bindCard", method = RequestMethod.POST)
    @ResponseBody
    public AjaxResult bindCard(String cardNo, String cardOwner) {
        String openid = WxMemoryCacheClient.getOpenid(request.getSession().getId());
        String checkResult = checkBindCardParam(openid, cardNo, cardOwner);
        if ("SUCCESS".equals(checkResult)) {
            AjaxResult bindResult = wxRechargeService.bindCard(openid, cardNo, cardOwner);
            return bindResult;
        } else {
            return AjaxResult.failure(checkResult);
        }
    }

    private String checkBindCardParam(String openid, String cardNo, String cardOwner) {
        if (StringUtils.isEmpty(openid) || StringUtils.isEmpty(cardNo) || StringUtils.isEmpty(cardOwner)) {
            return "未得到微信授权或者卡号、持卡人不能为空";
        }
        return "SUCCESS";
    }

    @RequestMapping(value = "/createOrder", method = RequestMethod.GET)
    public void createOrder(Long amount) throws IOException {
        String channelId = "WX_JSAPI";
        log.info("{}支付通过{}方式{}分", "微信", channelId, amount);
        // 判断是否拿到openid，如果没有则去获取
        String openId = WxMemoryCacheClient.getOpenid(request.getSession().getId());
        if (StringUtil.isNotEmpty(openId)) {
            UnionCardAccount unionCardAccount = wxRechargeService.getCardAccount(openId);
            DefaultKeyGenerator keyGenerator = new DefaultKeyGenerator();
            WxpayOrder wxpayOrder = new WxpayOrder();
            wxpayOrder.setId(keyGenerator.generateKey().longValue());
            wxpayOrder.setAmount(amount);
            wxpayOrder.setCurrency("cny");
            wxpayOrder.setMchId(MCH_ID);
            wxpayOrder.setMchOrderNo("" + keyGenerator.generateKey().longValue());
            wxpayOrder.setChannelId(channelId);
            wxpayOrder.setClientIp("192.168.210.254");
            wxpayOrder.setDevice("WEB");
            wxpayOrder.setSubject("一卡通充值" + amount + "分");
            wxpayOrder.setBody(wxpayOrder.getSubject());
            wxpayOrder.setNotifyUrl("");
            wxpayOrder.setParam1("");
            wxpayOrder.setParam2("");
            wxpayOrder.setOpenId(openId);
            wxpayOrder.setCardNo(unionCardAccount.getCardNo());
            wxpayOrder.setChannelMchId("");
            wxpayOrder.setStatus(PayConstant.PAY_STATUS_INIT);
            wxpayOrder.setCreateDate(new Date());
            wxpayOrder.setUpdateDate(new Date());
            int insertCount = wxRechargeService.saveWxPayOrder(wxpayOrder);
            if (insertCount == 1) {
                //TODO:正式的微信支付配置信息
                WxPayConfig wxPayConfig = new WxPayConfig();
                wxPayConfig.setMchId("");
                wxPayConfig.setAppId("");
                wxPayConfig.setKeyPath(wxPayProperties.getCertRootPath() + File.separator + "certLocalPath");
                wxPayConfig.setMchKey("");
                wxPayConfig.setNotifyUrl(wxPayProperties.getNotifyUrl());
                wxPayConfig.setTradeType("WX_JSAPI");
                WxPayService wxPayService = new WxPayServiceImpl();
                wxPayService.setConfig(wxPayConfig);
                WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = buildUnifiedOrderRequest(wxpayOrder, wxPayConfig);
                WxPayUnifiedOrderResult wxPayUnifiedOrderResult;
                try {
                    wxPayUnifiedOrderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
                    wxpayOrder.setStatus(PayConstant.PAY_STATUS_PAYING);
                    wxpayOrder.setChannelOrderNo(wxPayUnifiedOrderResult.getPrepayId());
                    wxpayOrder.setPaySuccTime(System.currentTimeMillis());
                    int updateCount = wxRechargeService.updatePayOrderStatus(wxpayOrder);
                    if (updateCount == 1) {
                        log.info("更新支付单状态为支付中，单号[{}]", wxpayOrder.getId());
                    }
                    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
                    String nonceStr = String.valueOf(System.currentTimeMillis());
                    Map<String, String> payInfo = new HashMap<>();
                    payInfo.put("appId", wxPayUnifiedOrderResult.getAppid());
                    payInfo.put("timeStamp", timestamp);
                    payInfo.put("nonceStr", nonceStr);
                    payInfo.put("package", "prepay_id=" + wxPayUnifiedOrderResult.getPrepayId());
                    payInfo.put("signType", WxPayConstants.SignType.MD5);
                    response.sendRedirect("/views/mp/recharge/rechargeConfirm.html?appId=" + payInfo.get("appId")
                            + "&timeStamp=" + payInfo.get("timeStamp") + "&nonceStr=" + payInfo.get("nonceStr") + "&package=" + payInfo.get("package")
                            + "&signType=" + payInfo.get("signType") + "&paySign=" + SignUtils.createSign(payInfo, wxPayConfig.getMchKey(), null));
                    log.info("下单成功，支付单号：[{}]", wxpayOrder.getId());
                } catch (WxPayException e) {
                    log.error("微信下单异常", e);
                    response.sendRedirect("/views/mp/recharge/failure.html?msg=" + e.getErrCodeDes());
                }
            } else {
                response.sendRedirect("/views/mp/recharge/failure.html?msg=" + Constants.MSG_ERROR);
            }
        } else {
            response.sendRedirect("/views/mp/recharge/failure.html?msg=" + Constants.MSG_ERROR);
        }
        response.sendRedirect("/views/mp/recharge/failure.html");
    }


    @RequestMapping(value = "/getCardInfo", method = RequestMethod.GET)
    @ResponseBody
    public AjaxResult getCardInfo() {
        String openid = WxMemoryCacheClient.getOpenid(request.getSession().getId());
        UnionCardAccount cardAccount = wxRechargeService.getCardAccount(openid);
        if (cardAccount != null) {
            return AjaxResult.success(cardAccount);
        } else {
            return AjaxResult.failure("获取充值卡信息失败，没法充值");
        }
    }


    @ResponseBody
    @RequestMapping(value = "/rechargeRecord", method = RequestMethod.POST)
    public AjaxResult rechargeRecord(RechargeOrder rechargeOrder) {
        String openid = WxMemoryCacheClient.getOpenid(request.getSession().getId());
        rechargeOrder.setOpenid(openid);
        List<RechargeOrder> orderList = wxRechargeService.gerRechargeListByPage(rechargeOrder);
        return getResult(rechargeOrder, orderList);
    }


    @ResponseBody
    @RequestMapping(value = "/payRecord", method = RequestMethod.POST)
    public AjaxResult payRecord(PayRecord payRecord) {
        String openid = WxMemoryCacheClient.getOpenid(request.getSession().getId());
        payRecord.setOpenid(openid);
        List<PayRecord> payRecordList = wxRechargeService.getPayListByPage(payRecord);
        return getResult(payRecord, payRecordList);
    }

    WxPayUnifiedOrderRequest buildUnifiedOrderRequest(WxpayOrder payOrder, WxPayConfig wxPayConfig) {
        String tradeType = wxPayConfig.getTradeType();
        String payOrderId = "" + payOrder.getId();
        Integer totalFee = payOrder.getAmount().intValue();// 支付金额,单位分
        String deviceInfo = payOrder.getDevice();
        String body = payOrder.getBody();
        String detail = null;
        String attach = null;
        String outTradeNo = payOrderId;
        String feeType = "CNY";
        String spBillCreateIP = payOrder.getClientIp();
        String timeStart = null;
        String timeExpire = null;
        String goodsTag = null;
        String notifyUrl = wxPayConfig.getNotifyUrl();
        String productId = null;
        String limitPay = null;
        String openId = payOrder.getOpenId();
        String sceneInfo = null;

        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setDeviceInfo(deviceInfo);
        request.setBody(body);
        request.setDetail(detail);
        request.setAttach(attach);
        request.setOutTradeNo(outTradeNo);
        request.setFeeType(feeType);
        request.setTotalFee(totalFee);
        request.setSpbillCreateIp(spBillCreateIP);
        request.setTimeStart(timeStart);
        request.setTimeExpire(timeExpire);
        request.setGoodsTag(goodsTag);
        request.setNotifyURL(notifyUrl);
        request.setTradeType(tradeType);
        request.setProductId(productId);
        request.setLimitPay(limitPay);
        request.setOpenid(openId);
        request.setSceneInfo(sceneInfo);

        return request;
    }

}
